﻿#region directives

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.Office.Interop.Outlook;
using Sync.Outlook;
using ToodleDo;
using Toodledo.Model;
using Toodledo.Model.API;
using Exception = System.Exception;

#endregion

namespace Sync
{
    internal class TaskSync
    {
        #region Members

        #endregion

        #region Constructors & Init

        #endregion

        #region Public Methods

        public static void Sync()
        {
            AddNewOutlookTasksToToodledo();
            DeleteLocalDeletesFromServer();
            GetNewAndChangedFromServer();
            DeleteServerDeletesfromLocal();
        }

        #endregion

        #region #Events & Invokables

        #endregion

        #region Private Methods

        private static void DeleteServerDeletesfromLocal()
        {
            //find out server deletes
            IEnumerable<DeletedItem> deletes = Remote.Tasks.GetDeleted(SyncSessionWrapper.SyncSession.LastAddEdit);
            Logger.InvokeMessageEvent(string.Format("deleting {0} tasks from outlook",deletes.Count()),Logger.MessageType.Tracking);
            foreach (TaskItem ti in deletes.Select(d => TasksItems.GetTaskItem(d.Id)))
            {
                try
                {
                    Logger.InvokeMessageEvent(String.Format("Deleting Outlook task: {0}", ti.Subject),Logger.MessageType.Tracking);
                    ti.Delete();
                }
                catch (Exception e)
                {
                    Logger.InvokeMessageEvent(e.Message,Logger.MessageType.Error);
                }
            }
        }


        private static void DeleteLocalDeletesFromServer()
        {            
            foreach (int id in SyncSessionWrapper.SyncSession.TaskIds.Where(id => !TasksItems.Contains(id)))
            {
                try
                {
                    Logger.InvokeMessageEvent(String.Format("Deleting Outlook task: {0}", id), Logger.MessageType.Tracking);
                    Remote.Tasks.DeleteTasks(new[] {id});
                }
                catch (Exception e)
                {
                    Logger.InvokeMessageEvent(e.Message, Logger.MessageType.Error);
                }
            }
        }

        private static void GetNewAndChangedFromServer()
        {            
            TaskQuery query = new TaskQuery
                                  {
                                      ModifiedAfter = SyncSessionWrapper.SyncSession.LastSyncUtc
                                  };
            TaskSet taskset = Remote.Tasks.GetTasks(query);
            foreach (Task task in taskset.Tasks)
            {
                if (TasksItems.Contains(task.Id))
                {
                    TasksItems.GetTaskItem(task.Id).Update(task);
                    Logger.InvokeMessageEvent(String.Format("Updating task to Outlook: {0}", task.Name), Logger.MessageType.Tracking);
                }
                else
                {
                    Logger.InvokeMessageEvent(String.Format("Adding task to Outlook: {0}", task.Name), Logger.MessageType.Tracking);
                    TasksItems.Add(task);
                }
            }
        }

        private static void AddNewOutlookTasksToToodledo()
        {                                   
            IEnumerable<TaskItem> newtasks = TasksItems.New;
                //TasksItems.NewTasksSince(((Session) Remote.General).Account.LastTaskEdit+t);//todo change it to local time!

            foreach (TaskItem taskItem in newtasks)
            {
                Task task = new Task {Tag = taskItem.EntryID};
                ApplyTaskDetails(task, taskItem);
                int id = Remote.Tasks.AddTask(task);
                Logger.InvokeMessageEvent(String.Format("Adding task to Toodledo: {0}", task.Name),
                                          Logger.MessageType.Tracking);
                taskItem.SetId(id);
                taskItem.Save();
            }
        }

        private static void ApplyTaskDetails(Task task, TaskItem taskItem)
        {
            task.Name = taskItem.Subject;

            if (taskItem.Categories != null)
            {
                string[] cats = taskItem.Categories.Split(',');
                task.Folder = SyncSessionWrapper.SyncSession.GetFolder(cats[0]);
            }
            DateTime outlooknone = new DateTime(4501, 1, 1, 0, 0, 0);
            DateTime toodlenone = new DateTime(1970, 1, 1, 0, 0, 0);
            task.Due = taskItem.DueDate == outlooknone ? toodlenone : taskItem.DueDate;
            task.Start = taskItem.StartDate == outlooknone ? toodlenone : taskItem.StartDate;
            task.Completed = taskItem.DateCompleted == outlooknone ? toodlenone : taskItem.DateCompleted;

            switch (taskItem.Importance)
            {
                case OlImportance.olImportanceLow:
                    task.Priority = Priority.Low;
                    break;
                case OlImportance.olImportanceNormal:
                    task.Priority = Priority.Medium;
                    break;
                case OlImportance.olImportanceHigh:
                    task.Priority = Priority.High;
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
            task.Note = taskItem.Body;
        }

        #endregion

        #region EventHandlers

        #endregion
    }
}